﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.ComponentModel;

namespace _4.RC4SymetricEncryptionAlgorithm
{
    public class EncryptionHelper
    {
        public static void RC4(string inputFile, string outputFile, string password)
        {
            using (FileStream inputFileStream = new FileStream(inputFile, FileMode.Open, FileAccess.Read))
            {
                using (FileStream outputFileStream = new FileStream(outputFile, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    RC4(inputFileStream, outputFileStream, password);
                }
            }
        }

        public static void RC4(Stream input, Stream output, string password)
        {
            byte[] key = GenerateRepeatKey(password);            
            byte[] buffer = new byte[key.Length];            

            while (input.Position != input.Length)
            {
                int readBytes = input.Read(buffer, 0, buffer.Length);
                RC4(buffer, key);
                output.Write(buffer, 0, readBytes);
            }
        }

        private static byte[] GenerateRepeatKey(string password)
        {
            byte[] key = Encoding.ASCII.GetBytes(password);

            int DesiredSize = 4096;
            int n;
            for (n = 1; n < DesiredSize; n++)
            {
                if (key.Length * n >= DesiredSize)
                {
                    break;
                }
            }
            byte[] repeatedKey = new byte[key.Length * n];

            for (int i = 0; i < n; i++)
            {
                key.CopyTo(repeatedKey, i * key.Length);
            }

            return repeatedKey;
        }

        // http://dotnet-snippets.com/dns/rc4-encryption-SID577.aspx
        public static void RC4(Byte[] buffer, Byte[] key)
        {            
            Byte[] s = new Byte[256];
            Byte[] k = new Byte[256];
            Byte temp;            

            for (int i = 0; i < 256; i++)
            {
                s[i] = (Byte)i;
                k[i] = key[i % key.GetLength(0)];
            }
            
            for (int i = 0, j = 0; i < 256; i++)
            {
                j = (j + s[i] + k[i]) % 256;
                temp = s[i];
                s[i] = s[j];
                s[j] = temp;
            }
            
            for (int x = 0, i = 0, j = 0; x < buffer.GetLength(0); x++)
            {
                i = (i + 1) % 256;
                j = (j + s[i]) % 256;
                temp = s[i];
                s[i] = s[j];
                s[j] = temp;
                int t = (s[i] + s[j]) % 256;
                buffer[x] ^= s[t];
            }            
        }

    }
}
